package com.starbaba.weixin.service.impl;

import com.base.common.database.BaseDao;
import com.base.common.database.DaoHelper;
import com.base.common.exception.AppException;
import com.base.common.log.LogService;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import com.starbaba.model.dictionary.Constant;
import com.starbaba.weixin.model.WeixinMenu;
import com.starbaba.weixin.model.WeixinMenuDbVO;
import com.starbaba.weixin.model.WeixinMenuRoot;
import com.starbaba.weixin.model.WeixinMenuVO;
import com.starbaba.weixin.service.WeixinMenuService;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @author Yukinomiu
 * @version 1.0
 */
@Service("WeixinMenuServiceImpl")
public class WeixinMenuServiceImpl implements WeixinMenuService {

    private static final String LOGGER_NAME = WeixinMenuServiceImpl.class.getName();

    private BaseDao baseDao = new BaseDao(Constant.POOL_LIFE);

    private JsonObject convertVO2Json(WeixinMenuVO vo) {
        JsonObject json = new JsonObject();
        JsonPrimitive name = new JsonPrimitive(vo.getDisplayName());
        json.add("name", name);

        if (vo.getSubList() == null || vo.getSubList().size() == 0) {
            String rawType = vo.getType().toLowerCase();
            String rawParam = vo.getParam();

            JsonPrimitive type = new JsonPrimitive(rawType);
            JsonPrimitive param = new JsonPrimitive(rawParam);
            json.add("type", type);

            switch (rawType) {
                case "view": {
                    json.add("url", param);
                    break;
                }

                case "click": {
                    json.add("key", param);
                    break;
                }

                default: {
                    throw new IllegalArgumentException("unsupported menu type");
                }
            }
        }
        else {
            JsonArray array = new JsonArray();
            json.add("sub_button", array);

            for (WeixinMenuVO v : vo.getSubList()) {
                JsonObject obj = convertVO2Json(v);
                array.add(obj);
            }
        }

        return json;
    }

    private WeixinMenuVO convertJson2VO(JsonObject json) {
        WeixinMenuVO vo = new WeixinMenuVO();

        String name = json.getAsJsonPrimitive("name").getAsString();
        vo.setDisplayName(name);

        JsonArray array = json.getAsJsonArray("sub_button");
        if (array == null || array.size() == 0) {
            String type = json.getAsJsonPrimitive("type").getAsString().toLowerCase();
            vo.setType(type);

            String param;
            switch (type) {
                case "view": {
                    param = json.getAsJsonPrimitive("url").getAsString();
                    break;
                }

                case "click": {
                    param = json.getAsJsonPrimitive("key").getAsString();
                    break;
                }

                default: {
                    throw new IllegalArgumentException("unsupported menu type");
                }
            }
            vo.setParam(param);
        }
        else {
            ArrayList<WeixinMenuVO> list = new ArrayList<>();
            vo.setSubList(list);
            for (JsonElement e : array) {
                JsonObject obj = e.getAsJsonObject();
                WeixinMenuVO v = convertJson2VO(obj);
                list.add(v);
            }
        }
        return vo;
    }

    private void saveVO(WeixinMenuVO vo, Long parentId, long rootId, int index) throws AppException {
        if (vo.getSubList() == null || vo.getSubList().size() == 0) {
            WeixinMenu menu = new WeixinMenu();

            menu.setRootId(rootId);
            menu.setIndex(index);

            menu.setMenuRole(WeixinMenu.MENU_ROLE_SINGLE);
            menu.setDisplayName(vo.getDisplayName());
            menu.setParentId(parentId);

            String type = vo.getType().toLowerCase();
            menu.setActionType("view".equals(type) ? WeixinMenu.ACTION_TYPE_VIEW : ("click".equals(type) ? WeixinMenu.ACTION_TYPE_CLICK : WeixinMenu.ACTION_TYPE_UNKNOWN));
            menu.setActionParam(vo.getParam());
            baseDao.add(menu);
        }
        else {
            WeixinMenu menu = new WeixinMenu();

            menu.setRootId(rootId);
            menu.setIndex(index);

            menu.setMenuRole(WeixinMenu.MENU_ROLE_COMBINE);
            menu.setDisplayName(vo.getDisplayName());
            menu.setParentId(parentId);

            menu.setActionType(null);
            menu.setActionParam(null);
            long tmpParentId = baseDao.addReturnGeneratedKey(menu);
            int tmpIndex = 0;
            for (WeixinMenuVO v : vo.getSubList()) {
                saveVO(v, tmpParentId, rootId, tmpIndex++);
            }
        }
    }

    private WeixinMenuVO getVO(WeixinMenu menu) throws AppException {
        WeixinMenuVO vo = new WeixinMenuVO();
        vo.setDisplayName(menu.getDisplayName());

        Integer role = menu.getMenuRole();
        if (role == WeixinMenu.MENU_ROLE_SINGLE) {
            String type;
            switch (menu.getActionType()) {
                case WeixinMenu.ACTION_TYPE_VIEW: {
                    type = "view";
                    break;
                }

                case WeixinMenu.ACTION_TYPE_CLICK: {
                    type = "click";
                    break;
                }

                case WeixinMenu.ACTION_TYPE_UNKNOWN: {
                    throw new AppException(-1, "unknown menu type");
                }

                default: {
                    throw new AppException(-1, "unsupported menu type");
                }
            }

            vo.setType(type);
            vo.setParam(menu.getActionParam());
            vo.setSubList(null);
        }
        else if (role == WeixinMenu.MENU_ROLE_COMBINE) {
            ArrayList<WeixinMenuVO> voList = new ArrayList<>();
            vo.setSubList(voList);

            List<WeixinMenu> menuList = baseDao.list("select * from loan.weixin_menu_item i where i.parentid = ? order by i.idx asc", WeixinMenu.class, menu.getId());
            for (WeixinMenu m : menuList) {
                WeixinMenuVO v = getVO(m);
                voList.add(v);
            }
        }
        else {
            throw new AppException(-1, "unsupported menu role");
        }

        return vo;
    }

    @Override
    public String toString(WeixinMenuVO vo) {
        return this.convert(vo).toString();
    }

    @Override
    public WeixinMenuVO convert(JsonObject json) {
        WeixinMenuVO root = new WeixinMenuVO();
        ArrayList<WeixinMenuVO> rootList = new ArrayList<>();
        root.setSubList(rootList);

        JsonArray array = json.getAsJsonArray("button");
        for (JsonElement e : array) {
            JsonObject obj = e.getAsJsonObject();
            WeixinMenuVO vo = convertJson2VO(obj);
            rootList.add(vo);
        }

        return root;
    }

    @Override
    public JsonObject convert(WeixinMenuVO vo) {
        JsonObject json = new JsonObject();
        JsonArray button = new JsonArray();
        json.add("button", button);
        for (WeixinMenuVO v : vo.getSubList()) {
            JsonObject obj = convertVO2Json(v);
            button.add(obj);
        }

        return json;
    }

    @Override
    public Long save(WeixinMenuVO vo, String remark, Integer weixinType) throws AppException {
        Long rootId;
        DaoHelper.startTransaction();
        try {
            WeixinMenuRoot root = new WeixinMenuRoot();
            root.setWeixinType(weixinType);
            root.setRemark(remark);
            root.setCreateTime(new Date());

            rootId = baseDao.addReturnGeneratedKey(root);
            int index = 0;
            for (WeixinMenuVO v : vo.getSubList()) {
                saveVO(v, null, rootId, index++);
            }

            DaoHelper.commitTransaction();
        } catch (Exception e) {
            DaoHelper.rollbackTransaction();
            LogService.error(LOGGER_NAME + ": 保存菜单异常", e);
            throw e;
        }
        return rootId;
    }

    @Override
    public WeixinMenuDbVO getMenuByRootId(Long rootId) throws AppException {
        WeixinMenuRoot root = baseDao.get("select * from loan.weixin_menu_root r where r.id = ?", WeixinMenuRoot.class, rootId);
        if (root == null) return null;
        List<WeixinMenu> menuList = baseDao.list("select * from loan.weixin_menu_item i where i.rootid = ? and i.parentid is null order by i.idx asc", WeixinMenu.class, rootId);

        WeixinMenuVO vo = new WeixinMenuVO();
        ArrayList<WeixinMenuVO> voList = new ArrayList<>();
        vo.setSubList(voList);
        for (WeixinMenu m : menuList) {
            voList.add(getVO(m));
        }

        return new WeixinMenuDbVO(root, vo);
    }

    @Override
    public WeixinMenuDbVO getLastMenuConfig(Integer weixinType) throws AppException {
        long rootId = (long) baseDao.getInt("select max(r.id) from loan.weixin_menu_root r where r.weixintype = ?", weixinType);
        if (rootId == 0) return null;
        return this.getMenuByRootId(rootId);
    }

    /*public static void main(String[] args) throws AppException {
        WeixinMenuService service = new WeixinMenuServiceImpl();

        WeixinMenuVO f1 = new WeixinMenuVO("菜单1-1", "click", "key1-1", null);
        WeixinMenuVO f2 = new WeixinMenuVO("菜单1-2", "click", "key1-2", null);
        WeixinMenuVO f3 = new WeixinMenuVO("菜单1-3", "view", "http://xmiles.cn", null);
        WeixinMenuVO f4 = new WeixinMenuVO("菜单1-4", "click", "key1-4", null);

        ArrayList<WeixinMenuVO> fList = new ArrayList<>();
        fList.add(f1);
        fList.add(f2);
        fList.add(f3);
        fList.add(f4);

        WeixinMenuVO f = new WeixinMenuVO("菜单1", "click", "key1", fList);
        WeixinMenuVO s = new WeixinMenuVO("菜单2", "view", "http://xmiles.cn", null);
        WeixinMenuVO t = new WeixinMenuVO("菜单3", "click", "key3", null);

        ArrayList<WeixinMenuVO> rootList = new ArrayList<>();
        rootList.add(f);
        rootList.add(s);
        rootList.add(t);
        WeixinMenuVO root = new WeixinMenuVO(null, null, null, rootList);

        String rootString = service.toString(root);
        String convertRootString = service.convert(root).toString();
        System.out.println(rootString.equals(convertRootString));

        WeixinMenuVO vo = service.convert(service.convert(root));
        String convertString = service.toString(vo);
        System.out.println(rootString.equals(convertString));

        long rootId = service.save(root, "测试菜单", WeixinMenuRoot.WEIXIN_TYPE_SERVICE);
        WeixinMenuDbVO dbVO = service.getMenuByRootId(rootId);
        String loadString = service.toString(dbVO.getMenuVO());

        System.out.println(rootString);
        System.out.println(loadString);
        System.out.println(rootString.equals(loadString));

        System.out.println("==========");
        System.out.println(service.getLastMenuConfig(WeixinMenuRoot.WEIXIN_TYPE_SERVICE));
    }*/
}
